﻿using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Asset加载管理
/// </summary>
public static class AssetManager
{
    /// <summary>
    /// 更新入口
    /// </summary>
    public static void Update()
    {
        UpdateTaskes();
    }

    static string CheckPathExtension(string path)
    {
        if (path == LoadManager.DATA)
            return path;

        if (!path.EndsWith(LuaFramework.AppConst.ExtName))
            path += LuaFramework.AppConst.ExtName;

        return path;
    }
    
#if UNITY_EDITOR
    static Object LoadAssetAtPath(string path, string name, System.Type assetType)
    {
        var fullPath = LoadManager.rootPath + "/" + path;
        if (!string.IsNullOrEmpty(name) && path.IndexOf('.') < 0)
            fullPath = fullPath + "/" + name;

        var asset = UnityEditor.AssetDatabase.LoadAssetAtPath(fullPath, assetType);
        if (asset == null)
            Debug.LogErrorFormat("asset {0} is not exist!", fullPath);

        return asset;
    }
#endif

    #region 同步加载
    /// <summary>
    /// 同步加载Asset
    /// </summary>
    /// <typeparam name="T">Asset类型</typeparam>
    /// <param name="path">AssetBundle路径</param>
    /// <param name="name">指定AssetBundle中哪个Asset，为空时为第一个</param>
    /// <param name="source">资源来源</param>
    /// <returns>返回Asset对象，使用完毕需要调用UnloadAsset接口销毁</returns>
    public static Object Load(string path, string name = null, System.Type assetType = null, LoadSource source = LoadSource.Auto)
    {
        var task = LoadTask(path, name, assetType, source);
        return task != null ? (Object)task.resource : null;
    }

    public static T Load<T>(string path, string name = null, LoadSource source = LoadSource.Auto) where T : Object
    {
        return (T)Load(path, name, typeof(T), source);
    }

    /// <summary>
    /// 同步加载Asset
    /// </summary>
    /// <typeparam name="T">Asset类型</typeparam>
    /// <param name="path">AssetBundle路径</param>
    /// <param name="name">指定AssetBundle中哪个Asset，为空时为第一个</param>
    /// <param name="cache">缓存方式</param>
    /// <param name="source">资源来源</param>
    /// <returns>返回加载任务对象</returns>
    public static LoadTaskR LoadTask(string path, string name = null, System.Type assetType = null, LoadSource source = LoadSource.Auto)
    {
        if (assetType == null)
            assetType = typeof(Object);

#if UNITY_EDITOR
        if (LoadManager.loadFromEditor)
        {
            var task1 = new AssetTask();
            task1.path = path;
            task1.name = name;
            task1.source = source;
            task1.SetDone(LoadAssetAtPath(path, name, assetType));
            return new LoadTaskR(task1);
        }
#endif

        path = CheckPathExtension(path);

        AssetTask task = null; 

        var bundleTask = BundleManager.LoadTask(path, source);
        if (bundleTask == null || bundleTask.resource == null)
            return null;

        var bundle = (AssetBundle)bundleTask.resource;
        var tag1 = name;
        if (string.IsNullOrEmpty(tag1))
        {
            var names = bundle.GetAllAssetNames();
            tag1 = names[0];
        }

        var asset = bundle.LoadAsset(tag1, assetType);
        if (asset == null)
        {
            return null;
        }

        task = FindLoadTask(path, name, source);
        if (task == null)
        {
            task = new AssetTask();
            task.path = path;
            task.name = name;
            task.source = source;
        }

        task.SetDone(asset);
        task.bundleTask = bundleTask;
        return new LoadTaskR(task);
    }
    #endregion

    #region 异步加载
    // 加载中的任务
    static List<AssetTask> m_Taskes = new List<AssetTask>();
    public static List<AssetTask> taskes
    {
        get { return m_Taskes; }
    }

    /// <summary>
    /// 正在加载任务数目
    /// </summary>
    public static int taskCount
    {
        get { return m_Taskes.Count; }
    }

    /// <summary>
    /// 异步加载Asset
    /// </summary>
    /// <param name="path">AssetBundle路径</param>
    /// <param name="name">指定AssetBundle中哪个Asset，为空时为第一个</param>
    /// <param name="assetType">资源类型</param>
    /// <param name="onFinish">加载完成回调</param>
    /// <param name="cache">缓存方式</param>
    /// <param name="source">资源来源</param>
    /// <param name="priority">加载优先级</param>
    /// <returns>返回加载任务对象</returns>
    public static LoadTaskR LoadAsync(string path, string name = null, System.Type assetType = null, LoadSource source = LoadSource.Auto)
    {
        if (assetType == null)
            assetType = typeof(Object);

#if UNITY_EDITOR
        if (LoadManager.loadFromEditor)
        {
            var task1 = new AssetTask();
            task1.path = path;
            task1.name = name;
            task1.resourceType = assetType;
            task1.source = source;
            var taskr = new LoadTaskR(task1);
            task1.SetDone(LoadAssetAtPath(path, name, assetType));
            return taskr;
        }
#endif
        
        path = CheckPathExtension(path);

        AssetTask task = FindLoadTask(path, name, source);
        if (task != null)
        {
            return new LoadTaskR(task);
        }

        var bundleTask = BundleManager.LoadAsync(path, source);
        if (bundleTask == null)
        {
            Debug.LogWarning("Load Bundle Failed " + path);
            return null;
        }

        //Debug.LogWarning("Load asset " + path);
        task = new AssetTask();
        task.bundleTask = bundleTask;
        task.path = path;
        task.name = name;
        task.resourceType = assetType;
        task.source = source;
        m_Taskes.Add(task);
        return new LoadTaskR(task);
    }

    /// <summary>
    /// 查找加载中的任务
    /// </summary>
    public static AssetTask FindLoadTask(string path, string name, LoadSource source = LoadSource.Auto)
    {
        foreach (var task in taskes)
        {
            if (task.PathEquals(path, name, source))
                return task;
        }
        return null;
    }

    static void UpdateTaskes()
    {
        for (int i = m_Taskes.Count - 1; i >= 0; --i)
        {
            var task = m_Taskes[i];

            task.Update();
            if (task.isDone)
            {
                m_Taskes.RemoveAt(i);
                //if (string.IsNullOrEmpty(task.error))
                //{
                //    Debug.Log("Load " + task.path + " done " + Time.time);
                //}
            }
        }
    }
    #endregion
}
